"use strict";

exports.__esModule = true;
require("core-js/modules/es.error.cause.js");
var _templateLiteralTag = require("../../helpers/templateLiteralTag");
var _object = require("../../helpers/object");
var _localHooks = _interopRequireDefault(require("../../mixins/localHooks"));
var _element = require("../../helpers/dom/element");
var _a11y = require("../../helpers/a11y");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); }
function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }
function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; }
function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
const DIALOG_CLASS_NAME = 'ht-dialog';
const TEMPLATE = `
<div data-ref="dialogElement" class="${DIALOG_CLASS_NAME}">
  <div data-ref="contentWrapperElement" class="${DIALOG_CLASS_NAME}__content-wrapper">
    <div data-ref="contentElement" class="${DIALOG_CLASS_NAME}__content"></div>
  </div>
</div>
`;

/**
 * DialogUI is a UI component that renders and manages dialog elements.
 * It handles dialog creation, content updates, visibility toggling, and styling.
 *
 * @private
 * @class DialogUI
 */
var _rootElement = /*#__PURE__*/new WeakMap();
var _refs = /*#__PURE__*/new WeakMap();
var _isRtl = /*#__PURE__*/new WeakMap();
class DialogUI {
  constructor(_ref) {
    let {
      rootElement,
      isRtl
    } = _ref;
    /**
     * The root element where the dialog UI will be installed.
     *
     * @type {HTMLElement}
     */
    _classPrivateFieldInitSpec(this, _rootElement, void 0);
    /**
     * The references to the UI elements.
     *
     * @type {object}
     */
    _classPrivateFieldInitSpec(this, _refs, void 0);
    /**
     * Indicates if the UI is in RTL mode.
     *
     * @type {boolean}
     */
    _classPrivateFieldInitSpec(this, _isRtl, false);
    _classPrivateFieldSet(_rootElement, this, rootElement);
    _classPrivateFieldSet(_isRtl, this, isRtl);
    this.install();
  }

  /**
   * Creates the dialog UI elements and sets up the structure.
   */
  install() {
    var _classPrivateFieldGet2;
    if ((_classPrivateFieldGet2 = _classPrivateFieldGet(_refs, this)) !== null && _classPrivateFieldGet2 !== void 0 && _classPrivateFieldGet2.dialogElement) {
      return;
    }
    const elements = (0, _templateLiteralTag.html)`${TEMPLATE}`;
    _classPrivateFieldSet(_refs, this, elements.refs);
    const {
      dialogElement
    } = _classPrivateFieldGet(_refs, this);
    dialogElement.addEventListener('click', () => this.runLocalHooks('clickDialogElement'));

    // Set ARIA attributes
    (0, _element.setAttribute)(dialogElement, [(0, _a11y.A11Y_MODAL)(), (0, _a11y.A11Y_TABINDEX)(-1), ['dir', _classPrivateFieldGet(_isRtl, this) ? 'rtl' : 'ltr']]);

    // Append to Handsontable after table grid element
    _classPrivateFieldGet(_rootElement, this).after(elements.fragment);
  }

  /**
   * Returns the dialog element.
   *
   * @returns {HTMLElement} The dialog element.
   */
  getDialogElement() {
    return _classPrivateFieldGet(_refs, this).dialogElement;
  }

  /**
   * Checks if the given element is inside the dialog.
   *
   * @param {HTMLElement} element - The element to check.
   * @returns {boolean} Returns `true` if the element is inside the dialog, `false` otherwise.
   */
  isInsideDialog(element) {
    return _classPrivateFieldGet(_refs, this).dialogElement.contains(element);
  }

  /**
   * Updates the dialog content and class name.
   *
   * @param {object} options - Class name update options.
   * @param {boolean} options.isVisible - Whether the dialog is visible.
   * @param {string|HTMLElement} options.content - The content to render in the dialog.
   * @param {string} options.customClassName - The custom class name to add to the dialog.
   * @param {string} options.background - The background to add to the dialog.
   * @param {boolean} options.contentBackground - Whether to show content background.
   * @param {boolean} options.animation - Whether to add the animation class to the dialog.
   * @param {object} options.a11y - The accessibility options for the dialog.
   *
   * @returns {DialogUI} The instance of the DialogUI.
   */
  updateDialog(_ref2) {
    let {
      isVisible,
      content,
      customClassName,
      background,
      contentBackground,
      animation,
      a11y
    } = _ref2;
    const {
      dialogElement,
      contentElement
    } = _classPrivateFieldGet(_refs, this);

    // Dialog class name
    const customClass = customClassName ? ` ${customClassName}` : '';
    const backgroundClass = background ? ` ${DIALOG_CLASS_NAME}--background-${background}` : '';
    const animationClass = animation ? ` ${DIALOG_CLASS_NAME}--animation` : '';
    const showClass = isVisible ? ` ${DIALOG_CLASS_NAME}--show` : '';

    // Update dialog class name
    dialogElement.className = `${DIALOG_CLASS_NAME}${customClass}${backgroundClass}${animationClass}${showClass}`;

    // Dialog aria attributes
    (0, _element.setAttribute)(dialogElement, [a11y.role === 'alertdialog' ? (0, _a11y.A11Y_ALERTDIALOG)() : (0, _a11y.A11Y_DIALOG)()]);
    if (a11y.ariaLabel && !a11y.ariaLabelledby) {
      (0, _element.setAttribute)(dialogElement, [a11y.ariaLabel ? (0, _a11y.A11Y_LABEL)(a11y.ariaLabel) : undefined]);
    } else {
      (0, _element.removeAttribute)(dialogElement, 'aria-label');
    }
    if (a11y.ariaLabelledby) {
      (0, _element.setAttribute)(dialogElement, [(0, _a11y.A11Y_LABELED_BY)(a11y.ariaLabelledby)]);
    } else {
      (0, _element.removeAttribute)(dialogElement, 'aria-labelledby');
    }
    if (a11y.ariaDescribedby) {
      (0, _element.setAttribute)(dialogElement, [(0, _a11y.A11Y_DESCRIBED_BY)(a11y.ariaDescribedby)]);
    } else {
      (0, _element.removeAttribute)(dialogElement, 'aria-describedby');
    }

    // Dialog content class name
    const contentBackgroundClass = contentBackground ? ` ${DIALOG_CLASS_NAME}__content--background` : '';

    // Update content class name
    contentElement.className = `${DIALOG_CLASS_NAME}__content${contentBackgroundClass}`;

    // Clear existing dialog content
    contentElement.innerHTML = '';

    // Render new dialog content
    if (typeof content === 'string') {
      (0, _element.fastInnerHTML)(contentElement, content);
    } else if (content instanceof HTMLElement || content instanceof DocumentFragment) {
      contentElement.appendChild(content);
    }
    return this;
  }

  /**
   * Shows the dialog with optional animation.
   *
   * @param {boolean} animation - Whether to add the animation class to the dialog.
   * @returns {DialogUI} The instance of the DialogUI.
   */
  showDialog(animation) {
    const {
      dialogElement
    } = _classPrivateFieldGet(_refs, this);
    dialogElement.style.display = 'block';
    if (animation) {
      // Triggers style and layout recalculation, so the display: block is fully committed before adding
      // the class ht-dialog--show.
      // eslint-disable-next-line no-unused-expressions
      dialogElement.offsetHeight;
    }
    (0, _element.addClass)(dialogElement, `${DIALOG_CLASS_NAME}--show`);
    return this;
  }

  /**
   * Hides the dialog with optional animation.
   *
   * @param {boolean} animation - Whether to add the animation class to the dialog.
   * @returns {DialogUI} The instance of the DialogUI.
   */
  hideDialog(animation) {
    const {
      dialogElement
    } = _classPrivateFieldGet(_refs, this);
    (0, _element.removeClass)(dialogElement, `${DIALOG_CLASS_NAME}--show`);
    if (animation) {
      dialogElement.addEventListener('transitionend', () => {
        if (!(0, _element.hasClass)(dialogElement, `${DIALOG_CLASS_NAME}--show`)) {
          dialogElement.style.display = 'none';
        }
      }, {
        once: true
      });
    } else {
      dialogElement.style.display = 'none';
    }
    return this;
  }

  /**
   * Focuses the dialog element.
   */
  focusDialog() {
    _classPrivateFieldGet(_refs, this).dialogElement.focus();
  }

  /**
   * Updates the width of the dialog container to the same size as the table.
   *
   * @param {number} width - The width of the table.
   * @returns {DialogUI} The instance of the DialogUI.
   */
  updateWidth(width) {
    _classPrivateFieldGet(_refs, this).dialogElement.style.width = `${width}px`;
    return this;
  }

  /**
   * Updates the height of the dialog container.
   *
   * @param {number} licenseInfoHeight - The height of the license info.
   * @returns {DialogUI} The instance of the DialogUI.
   */
  updateHeight(licenseInfoHeight) {
    _classPrivateFieldGet(_refs, this).dialogElement.style.height = `calc(100% - ${licenseInfoHeight}px)`;
    return this;
  }

  /**
   * Removes the dialog UI elements from the DOM and clears the refs.
   */
  destroyDialog() {
    var _classPrivateFieldGet3;
    (_classPrivateFieldGet3 = _classPrivateFieldGet(_refs, this)) === null || _classPrivateFieldGet3 === void 0 || _classPrivateFieldGet3.dialogElement.remove();
    _classPrivateFieldSet(_refs, this, null);
  }
}
exports.DialogUI = DialogUI;
(0, _object.mixin)(DialogUI, _localHooks.default);